
;; dashobj4.lsp
;;    MENUS, EXPAND-DATASHEET 
;; Copyright (c) 1994-2002 by Forrest W. Young



(defmeth datasheet-proto :ancestors 
  (ancestors self))

(defmeth datasheet-proto :show-datasheet ()
  (send self :show-window)
  t)

(defmeth datasheet-proto :switch-button-bar ()
  (send self :button-bar-showing? (not (send self :button-bar-showing?)))
  (cond 
    ((send self :button-bar-showing?)
     (send self :margin 0 (+ (second (send self :margin)) 21) 0 0)
     (send self :origin 0 (+ (second (send self :origin)) 18)))
    (t
     (send self :margin 0 0 0 0)
     (send self :origin 0 0)))
  (send self :redraw)
  (if (send self :button-bar-showing?)
      (send  dash-menu-button-bar :title "Hide Button Bar")
      (send  dash-menu-button-bar :title "Show Button Bar"))
  (send self :button-bar-showing?))




; for there to be a second menu in the datasheet window
; the window must be a container window. 
; all non-container-proto windows can only have one menu.  

#|
(defun dash-menubar (&key (in nil in?) (toolwindow t) (location '(100 200)) (size '(550 250)) (strip nil) (editable t) (hide nil))
"Args: (&key (in nil in?) (toolwindow t) (location '(100 200)) 
Creates menubar in container IN. If IN is not used, the menubar is a floating menubar (i.e., it is not in any window). If IN is bound to \"full\" the menubar is a not in any window, and is located at the top of the screen with a width equal to the screen width. If IN is explicitly set to NIL, the menubar is in in the XLispStat window. If IN is bound to an existing container, the menubar appears in that container. Appears at location LOCATION unless IN is \"full\"."
  (let* ((prev-container *active-container*)
         (mb) (menus)
         )
    (setf mb (container :in nil :localmenu t :toolwindow nil 
                           :title "DataSheet - " 
                           :size size :location  location))
    (send mb :top-most (not hide))
    (send mb :bottom-most hide)
    (setf *datasheet-menubar* mb)
    (send *datasheet-menubar* :add-slot 'menus 
          (add-datasheet-menubar :editable editable :container mb))
    (enable-container prev-container)
    (defmeth *datasheet-menubar* :menus (&optional (string nil set))
      (if set (setf (slot-value 'menus) string))
      (slot-value 'menus))
    (defmeth *datasheet-menubar* :close ()
      (call-next-method)
      (setf *datasheet-menubar* nil))
    (send mb :top-most t)
    (send mb :bottom-most nil)
    mb))

(defun dash-menubar (&key (data $) (in nil in?) (toolwindow t) (location '(100 200)) (size '(550 250)) (strip nil) (editable t) (hide nil))
"Args: (&key (in nil in?) (toolwindow t) (location '(100 200)) 
Creates menubar in container IN. If IN is not used, the menubar is a floating menubar (i.e., it is not in any window). If IN is bound to \"full\" the menubar is a not in any window, and is located at the top of the screen with a width equal to the screen width. If IN is explicitly set to NIL, the menubar is in in the XLispStat window. If IN is bound to an existing container, the menubar appears in that container. Appears at location LOCATION unless IN is \"full\"."
  (let* ((prev-container *active-container*)
         (mb) (menus)
         )
    (if in
      (enable-container (eval in))
      (setf mb (send data :create-spreadplot-container 1)))
   ; (setf mb (container :in nil :localmenu t :toolwindow nil 
   ;                        :title "DataSheet - " 
   ;                        :size size :location  location))
   ; (send mb :top-most (not hide))
   ; (send mb :bottom-most hide)
    (setf *datasheet-menubar* mb)
    (send *datasheet-menubar* :add-slot 'menus 
          (add-datasheet-menubar :editable editable :container mb))
    (enable-container prev-container)
    (defmeth *datasheet-menubar* :menus (&optional (string nil set))
      (if set (setf (slot-value 'menus) string))
      (slot-value 'menus))
    (defmeth *datasheet-menubar* :close ()
      (call-next-method)
      (setf *datasheet-menubar* nil))
    (send mb :top-most t)
    (send mb :bottom-most nil)
    mb))
|#

(defun dash-menubar (&key (data $) (container nil container?) (toolwindow t) (location '(100 200)) (size '(550 250)) (strip nil) (editable t) (hide nil) (pop-out nil)
             (in nil in??) (in? nil in???))
"Args: (&key (in nil in?) (toolwindow t) (location '(100 200)) 
Creates menubar in container IN. If IN is not used, the menubar is a floating menubar (i.e., it is not in any window). If IN is bound to \"full\" the menubar is a not in any window, and is located at the top of the screen with a width equal to the screen width. If IN is explicitly set to NIL, the menubar is in in the XLispStat window. If IN is bound to an existing container, the menubar appears in that container. Appears at location LOCATION unless IN is \"full\"."
  (setf in container)
  (setf in? container?)
  (let* ((prev-container *active-container*)
         (in? (if in??? in? in??))
         (graph-frame (graph-frame :show nil))
         (pop-out (send graph-frame :seen-in in in?))
         (container (if (equal pop-out t) graph-frame pop-out))
         (mb) (menus)
         )
    (if in?
        (enable-container (eval container))
        (setf mb (send data :create-spreadplot-container 1))
       ;(setf mb (container :in in :localmenu t :toolwindow nil 
       ;                     :title "DataSheet - " :show t
       ;                     :size size :location  location))
        )
   ; (send mb :show-window)
    (apply #'send mb :size size)
    
    ; (send mb :top-most (not hide))
   ; (send mb :bottom-most hide)
    (setf *datasheet-menubar* mb)
    (send *datasheet-menubar* :add-slot 'menus 
          (add-datasheet-menubar :editable editable :container mb))
    (enable-container prev-container)
    (defmeth *datasheet-menubar* :menus (&optional (string nil set))
      (if set (setf (slot-value 'menus) string))
      (slot-value 'menus))
    (defmeth *datasheet-menubar* :close ()
      (call-next-method)
      (setf *datasheet-menubar* nil))
    (send mb :top-most t)
    (send mb :bottom-most nil)
    mb))

(defun add-datasheet-menubar (&key (container nil) (mainwindow nil) (editable t))
  (let ((prev-container *active-container*))
    (when container (enable-container container))
    (let* ((temp-file-menu (cloan-menu *vista-file-menu*))
           (temp-data-menu (cloan-menu *data-menu*))
           (menu-list 
            (if (not editable)
                (list
                 (setf *datasheet-window-menu* 
                       (send datasheet-proto    :define-datasheet-window-menu))
                ;(setf *datasheet-file-menu*    (cloan-menu *vista-file-menu*))
                ; (setf *datasheet-edit-menu*    (cloan-menu *edit-menu*))
                 (make-datasheet-data-menu)
                 (setf *datasheet-trans-menu*   (cloan-menu *trans-menu*))
                 (setf *datasheet-tools-menu*   (cloan-menu *tools-menu*))
                 (setf *datasheet-model-menu*   (cloan-menu *model-menu*))
                 (setf *datasheet-help-menu*    (cloan-menu *help-menu*))
                 (setf *datasheet-dash-menu*    
                       (send datasheet-proto    :define-datasheet-menu))
                 )
                (list
                 (setf *datasheet-window-menu*  
                       (send datasheet-proto :define-datasheet-window-menu))
                 (setf *datasheet-data-menu*    
                       (send datasheet-proto :define-datasheet-data-menu))
                 (setf *datasheet-dash-menu*    
                       (send datasheet-proto :define-datasheet-menu))
                 (setf *datasheet-help-menu*    
                       (cloan-menu *help-menu*))))
            ))
      (if mainwindow (send *window-menubar-menu* :title "View"))
      (setf menu-list (remove 'nil menu-list))
      (mapcar #'(lambda (menu)
                  (send menu :install))
              menu-list)
      menu-list)))
                              

(defun desktop-window ()
  (if *hide-vista* (show-vista)
      (send *desktop-container* :show-window)))

(defmeth datasheet-proto :define-datasheet-window-menu ()
  (let* ((menu (send menu-proto :new "Window")))
    (send menu :append-items 
          (send menu-item-proto :new "DeskTop Window" 
                :action #'(lambda () (desktop-window)))
          (send expert-menu-item-proto :new "XLispStat Window"
                :action #'(lambda () (xlispstat-window)))
          )
    menu))



(defmeth datasheet-proto :define-dash-vartype-menu ()
  (let* ((menu (send menu-proto :new "VarType")))
    (send menu :append-items 
          (send menu-item-proto :new "Category" 
                :action #'(lambda () (make-catvar)))
          (send menu-item-proto :new "Ordinal"
                :action #'(lambda () (make-ordvar)))
         	(send dash-item-proto :new)	
          (send menu-item-proto :new "Numeric" 
                :enabled *current-data*
                :action #'(lambda () (make-numvar)))
          (send menu-item-proto :new "Frequency" 
                :enabled *current-data*
                :action #'(lambda () (make-freqvar)))
          )
    (setf *dash-vartype-menu* menu)
    menu))

(defmeth datasheet-proto :define-datasheet-data-menu ()
  (let* ((menu (send menu-proto :new "Data"))
         (dash self)
         (ovrl (first (send dash :overlays))))
    (send menu :append-items 
          (send expert-menu-item-proto :new "About These Data" 
                :action 'about-these-data)
          (send dash-item-proto :new)
          (send expert-menu-item-proto :new "Create Data Object"
                :enabled t
                :action #'(lambda () (create-data-object)))
          (send expert-menu-item-proto :new "Save Data As ..." :enabled t
                :action 'save-data-as)
          )
    menu))

(defmeth datasheet-proto :create-data ()
    (send self :save-as-new-dataobject))

(defmeth datasheet-proto :define-datasheet-popup-menu ()
  (let* ((actcon *active-container*)
         (nowcon (if (send self :container) 
                     (enable-container (send self :container))
                     (container :in nil :localmenu t 
                                :title "DashMenu Bar" 
                                :size '(250 18) :show nil)))
         (menu (send self :define-datasheet-menu t)))
    (enable-container actcon)
    menu))

;(defmeth datasheet-proto :statistical-object-type () "dash")


(defmeth datasheet-proto :define-datasheet-menu (&optional popup)
  (let* ((menu (send menu-proto :new "DataSheet"))
         (dash self)
         (data (send dash :data-object))
         (dash-menu-top-item (send expert-menu-item-proto :new "Always On Top"))
         (dash-menu-max-item  
          (send expert-menu-item-proto :new "Maximize"
                :action #'(lambda () (send dash :max-restore-menu-item-toggle))))
         (dash-menu-shrinkwrap-item  
          (send expert-menu-item-proto :new "Shrink Wrap"
                :action #'(lambda () (send dash :shrink-wrap? t)
                            (send dash :shrink-wrapper))
                :mark nil))
         (dash-menu-change-format-item
          (send expert-menu-item-proto :new "Change Column Format"
                :action #'(lambda () 
                             (unless (send dash :format)
                              (when (send self :shrink-wrap?)
                                    (apply #'send self :size
                                       (send self :shrink-wrap)))))))
         
         (dash-menu-desktop-window-item
          (send expert-menu-item-proto :new "DeskTop Window" 
                :action #'(lambda () (desktop-window))))
         (dash-menu-xlisp-window-item 
          (send expert-menu-item-proto :new "XLispStat Window"
                :action #'(lambda () (xlispstat-window))))
         
         )

    (send dash :dash-menu-top-item dash-menu-top-item)

    (defmeth dash-menu-top-item :action (&optional (arg nil arg?))
      (send dash-menu-top-item :mark
            (if arg? arg (not (send dash-menu-top-item :mark))))
      (send dash :top-most 
            (send dash-menu-top-item :mark))
      (send dash :bottom-most nil))


    (defmeth dash :max-restore-menu-item-toggle ()
      (cond
        ((equal (send dash-menu-max-item :title) "Maximize")
         (unless (send dash-menu-max-item :has-slot 'sizeloc)
                 (send dash-menu-max-item :add-slot 'sizeloc))
         (send dash-menu-max-item :slot-value 'sizeloc
               (list (send dash :size) (send dash :location)))
         (apply #'send dash :frame-size (effective-screen-size))
         (send dash :frame-location 0 0)
         (send dash-menu-max-item :title "Restore Down")
         )
        ((equal (send dash-menu-max-item :title) "Restore Down")
         (send dash-menu-max-item :title "Maximize")
         (apply #'send dash :location 
                (second (send dash-menu-max-item :slot-value 'sizeloc)))
         (apply #'send dash :size 
                (first (send dash-menu-max-item :slot-value 'sizeloc))))))

   
    (setf *dash-menu-top-item* dash-menu-top-item)
    
    (send menu :append-items 
          (send expert-menu-item-proto :new "DataSheet Help"
                :action #'(lambda () (datasheet-help))))

    (when popup
          (send menu :append-items
                (send expert-menu-item-proto :new "About These Data" 
                     ;:action 'about-these-data ;fwy changed 09-24-02 to following
                      :action #'(lambda ()
                                 ; (setcd (first (send @ :dob-parents)))
                                  (about-these-data)))))

    (send menu :append-items (send dash-item-proto :new))
    
    (when popup
          (send menu :append-items
                (send expert-menu-item-proto :new "Create Data Object" ;fwy changed 09-20-02
                      :enabled   t
                      :action #'(lambda () 
                                  (setcds dash)
                                  (create-data-object)
                                  ))
                (send expert-menu-item-proto :new "Save Data As ..."
                      :enabled   t
                      :action #'(lambda () 
                                  (setcds dash)
                                  (send dash :top-most nil)
                                  (send dash :save-data-as)
                                  (send dash :top-most 
                                        (send dash :dash-menu-top-item :mark))))
                (send dash-item-proto :new)))
    
    (send menu :append-items 
          dash-menu-change-format-item
          (send expert-menu-item-proto :new "Add Rows and/or Columns"
                :enabled t
                :action #'(lambda () (send dash :expand-datasheet))) 
          (send expert-menu-item-proto :new "Change Labels"
                :enabled t
                :action #'(lambda () (send dash :switch-label-variable)))
          (send expert-menu-item-proto :new "Change Matrix Names" 
                :enabled nil
                :action #'(lambda () (send dash :change-matrix-names)))
          (send dash-item-proto :new)
          dash-menu-top-item 
          dash-menu-shrinkwrap-item
          dash-menu-max-item)
    
    (when popup
          (send menu :append-items
                (send dash-item-proto :new)
                dash-menu-desktop-window-item
                dash-menu-xlisp-window-item))
         
   
    menu))
  
          
 (defmeth datasheet-proto :change-column-format ()
      (send self :format)
      (when (send self :shrink-wrap?)
            (apply #'send self :size (send self :shrink-wrap))))

(defmeth datasheet-proto :on-top (&optional (arg nil set))
"Arg logical
Sets both the top-most state of the window and the mark on the always-on-top menu item. Reports the state of the mark. Use the :top-most message to set the state of the window without effectingthe menu item mark"
  (let ((menu-item (send self :dash-menu-top-item)))
    (when set 
          (when menu-item (send menu-item :mark arg))
          (send self :top-most arg))
    (when menu-item (send menu-item :mark))))

(defmeth datasheet-proto :on-top (&optional (arg nil set)))


(defmeth datasheet-proto :expand-datasheet ()
  (when (not (equal *current-data* (send self :data-object)))
        (setcd (send self :data-object)))
  (let* ((mat (send (send self :data-object) :matrices))
         (obs-text (send text-item-proto :new 
              (format nil "Number of Additional ~a" 
                      (if mat "Rows and Columns" "Observations"))))
         (obs-str  (send edit-text-item-proto :new "0" :text-length 5))
         (var-text (send text-item-proto :new 
              (format nil "Number of Additional ~a"
                      (if mat "Matrices" "Variables"))))
         (var-str  (send edit-text-item-proto :new "0" :text-length 5))
         (ok (send modal-button-proto :new "OK"
                   :action (lambda ()
                             (list (send obs-str :text) (send var-str :text)))))
         (cancel (send modal-button-proto :new "Cancel"))
         (dialog (send modal-dialog-proto :new
                       (list (list obs-str obs-text)
                             (list var-str var-text)
                             (list ok cancel))))
         (result (send dialog :modal-dialog))
         (err)
         )
    (send dialog :title "Add Rows and/or Columns")
    (when result
          (setf result 
                (mapcar #'(lambda (value)
                            (cond 
                              ((= (length value) 0)(setf err t))
                              (t
                               (setf value (read-from-string value))
                               (when (or (not (numberp value))(< value 0))(setf err t))
                               value)))
                        result))
          (cond
            (err (vista-error-dialog "You must enter two non-negative numbers"))
            (mat
             (when (> (first result) 0) 
                   (send *datasheet* :expand-mat-datasheet t nil (first result)))
             (when (> (second result) 0) 
                   (send *datasheet* :expand-mat-datasheet nil t (second result))))
            (t
             (when (> (first result) 0) 
                   (send *datasheet* :expand-mv-datasheet nil t (first result)))
             (when (> (second result) 0) 
                   (send *datasheet* :expand-mv-datasheet t nil (second result))))))
    
    ))

(defmeth datasheet-proto :calculate-label-width ()
  (send self :label-width 
        (+ 7 (max (combine (mapcar #'(lambda (string) 
                                     (send self :text-width string))
                                 (send self :label-strings))
                         (send self :text-width (send self :datasize-string))
                         (send self :text-width (send self :datatype-string)))))))

(defmeth datasheet-proto :expand-labels (n &optional (obsname "Obs"))
  (let ((nobs (length (send self :label-strings))))
    (send self :label-strings 
          (append (send self :label-strings)
                  (mapcar #'(lambda (i) 
                              (format nil "~a~d" obsname (+ nobs i 1)))
                          (iseq n))))))

(defmeth datasheet-proto :expand-names (n name n-1)
  (let ((nvar (length (send self :variable-strings))))
    (send self :variable-strings 
          (append (send self :variable-strings)
                  (mapcar #'(lambda (i) (format nil "~a~d" name (if n-1 (+ nvar i)
                                                                    (+ nvar i 1))))
                          (iseq n))))))     

(defmeth datasheet-proto :expand-mv-datasheet (new-var new-obs n)
"Args: new-var new-obs n
Method to add N new variables (when NEW-VAR is t) and/or observations (when NEW-OBS is t) to a multivariate datasheet."
  (let* ((varname "Var")
         (obsname "Obs")
         (vartype "Category")
         (datum "---")
         (freq-datum "0")
         (vars (send self :variable-strings))
         (newstrs nil)
         (types (send self :type-strings))
         (labels (send self :label-strings))
         (nvar (send self :nvar))
         (nobs (send self :nobs))
         (last-varname (first (last vars)))
         (dob (send self :data-object))
         (data-type (first (datatype? dob t t)))
         (data-type (if (> (length data-type) 5) (select data-type (iseq 5)) data-type))
         (freq-way-names '("Row" "Column"))
         (n-1)
         (new-nvar (if new-var (+ n nvar) nvar))
         (new-nobs (if new-obs (+ n nobs) nobs))
         )
    (send self :datasize-string 
          (if (< (max (list new-nvar new-nobs)) 10)
             (format nil "Size:~d X ~d"  new-nobs new-nvar)
             (format nil "~d X ~d" new-nobs new-nvar )))
    (send self :datatype-string (format nil "Type:~a" data-type))
    (cond 
      ((equal data-type "class") (setf n-1 t))
      ((equal data-type "freq")
       (setf datum "0.")
       (setf vartype "Numeric")
       (setf varname (second freq-way-names))
       (setf obsname (first  freq-way-names))))
    (when (> (length last-varname) 4)
          (cond 
            ((equal (subseq last-varname 0 5) "Class")
             (setf varname "Class")
             (setf vartype "Category"))
            ((equal (subseq last-varname 0 5) "FreqV")
             (setf varname "FreqVar")
             (setf vartype "Numeric"))
            ))
    (when new-var
          (send self :nvar (+ nvar n))
          (send self :newvar (+ (send self :newvar) n))
          (send self :expand-names n varname n-1)
          (send self :type-strings (append types (repeat vartype n)))
          (send self :data-matrix-strings
                (bind-columns (send self :data-matrix-strings)
                              (matrix (list nobs n)
                                      (repeat datum (* nobs n)))))
          )
    (when new-obs
          (send self :nobs (+ nobs n))
          (send self :newobs (+ (send self :newobs) n))
          (send self :expand-labels n obsname)
          (send self :data-matrix-strings 
                (bind-rows (send self :data-matrix-strings) 
                           (matrix (list n nvar)
                                   (repeat datum (* n nvar)))))))
  (when *realtime-datasheet-update* (send self :save-datasheet nil nil 2))
  (send self :calculate-label-width)
  (send self :edited t)
  (send self :set-window-scroll-size new-obs new-var)
  (send self :redraw-now t)
  (send self :redraw))

(defmeth datasheet-proto :matrix-datasize-string (nvar nmat)
  (send self :datasize-string 
        (if (< (max (list nvar nmat)) 10)
            (if (= nmat 1)
                (format nil "Size:~d X ~d"  nvar nvar)
                (format nil "Size:(~d*~d) X ~d"  nvar nmat nvar))
            (if (= nmat 1)
                (format nil "Size:~d X ~d"  nvar nvar)
                (format nil "(~d*~d) X ~d"  nvar nmat nvar)))))

(defmeth datasheet-proto :expand-mat-datasheet (new-row&col new-mat n)
"Args: new-row&col new-mat
Method to add a new row and column (when new-row&col is t) or new matrix (when new-mat is t) to a matrix datasheet."
  (let* ((nvar (send self :nvar))
        (nobs (send self :nobs))
        (nmat (send self :nmat))
        (new-nvar (if new-row&col (1+ nvar) nvar))
        (new-nmat (if new-mat (1+ nmat) nmat))
        (types (send self :type-strings)))
   (send self :matrix-datasize-string new-nvar new-nmat)
    (when new-row&col
          (dotimes (i n) 
                   (send self :data-matrix-strings 
                         (send self :add-rows&col 
                               (send self :data-matrix-strings) 
                               (send self :nvar)
                               (send self :nmat)))
                   (send self :nvar (+ (send self :nvar) 1)))
          (send self :nobs (+ nobs (* n nmat)))
          (send self :newvar (+ n (send self :newvar)))
          (send self :newobs (+ (send self :newobs) (* n nmat)))
          (send self :expand-names n "RowCol" nil)
          (send self :type-strings (append types (repeat "Numeric" n)))
          (send self :label-strings nil)
          (send self :create-matrix-label-strings 0 (send self :nmat))
          )
    (when new-mat 
          (send self :nmat (+ nmat n))
          (send self :newmat (+ n (send self :newmat)))
          (send self :nobs (+ nobs (* n nvar)))
          (send self :newobs (+ (send self :newobs) (* n nvar)))
          (send self :matrix-strings 
                (append (send self :matrix-strings) 
                        (mapcar #'(lambda (i) 
                                    (format nil "~a~d" "Matrix" (+ nmat i 1)))
                                (iseq n))))
          (dotimes (i n)
                   (send self :data-matrix-strings
                         (bind-rows (send self :data-matrix-strings) 
                                    (make-array (list nvar nvar)
                                                :initial-element "NIL"))))
          (send self :create-matrix-label-strings nmat n)
          )    
    )
  
  (send self :calculate-label-width)
  (send self :edited t)
  (send self :set-window-scroll-size new-mat new-row&col)
  (send *datasheet* :redraw-now t)
  (send self :redraw))

(defmeth datasheet-proto :add-rows&col (themat nvar nmat)
  (let ((nobs (* nvar nvar))
        )
    (setf themat (bind-rows themat (repeat "NIL" nvar)))
    (when (> nmat 1) 
          (dotimes (i (- nmat 1))
                   (setf j (- nmat 1 i)) 
                   (setf rowin (* nvar j))
                   (setf themat 
                         (bind-rows 
                          (select themat (iseq rowin) (iseq nvar))
                          (repeat "NIL" nvar)
                          (select themat 
                                  (iseq rowin (- (first (size themat)) 1)) 
                                  (iseq nvar))))))
    (bind-columns themat (repeat "NIL" (first (size themat))))))

(defmeth datasheet-proto :clear ()
  (send self :needs-revealing t)
  (send self :isolate t))

(defmeth datasheet-proto :reveal ()
  (send self :needs-revealing nil)
  (send self :isolate nil))

(defmeth datasheet-proto :isolate (nilt)
"Isolates datasheet from activity while there is no corresponding data object. Used when delete data deletes all data objects, but desktop-datasheet remains visible."
  (cond
    (nilt
     (when (send self :editable)
           (send self :click-button 2))
     (defmeth self :redraw-content ())
     (defmeth (first (send self :overlays)) :do-click (x y m1 m2))
     (defmeth self :do-click (x y m1 m2))
     (send self :title "DataSheet")
     (send self :redraw))
    (t
     (defmeth (first (send self :overlays)) :do-click (x y m1 m2)
       (send self :real-do-click x y m1 m2))
     (defmeth self :do-click (x y m1 m2)
       (send self :real-do-click x y m1 m2))
     (defmeth self :redraw-content ()
       (send self :redraw-datasheet-content))
     (when (not (send self :editable))
           (send self :click-button 2))
     (send self :title (strcat "DataSheet - " 
                               (send (send self :data-object) :name)
                               " (DataType: "
                               (send (send self :data-object) :data-type)
                               ")"))
     (send self :redraw)
     ))
  )
